;(function (root, factory) {
  if (typeof exports === 'object') {
    // CommonJS
    module.exports = exports = factory()
  } else if (typeof define === 'function' && define.amd) {
    // AMD
    define([], factory)
  } else {
    // Global (browser)
    root.CryptoJS = factory()
  }
})(this, function () {
  /*globals window, global, require*/

  /**
   * CryptoJS core components.
   */
  var CryptoJS =
    CryptoJS ||
    (function (Math, undefined) {
      var crypto

      // Native crypto from window (Browser)
      if (typeof window !== 'undefined' && window.crypto) {
        crypto = window.crypto
      }

      // Native crypto in web worker (Browser)
      if (typeof self !== 'undefined' && self.crypto) {
        crypto = self.crypto
      }

      // Native crypto from worker
      if (typeof globalThis !== 'undefined' && globalThis.crypto) {
        crypto = globalThis.crypto
      }

      // Native (experimental IE 11) crypto from window (Browser)
      if (!crypto && typeof window !== 'undefined' && window.msCrypto) {
        crypto = window.msCrypto
      }

      // Native crypto from global (NodeJS)
      if (!crypto && typeof global !== 'undefined' && global.crypto) {
        crypto = global.crypto
      }

      // Native crypto import via require (NodeJS)
      if (!crypto && typeof require === 'function') {
        try {
          crypto = require('crypto')
        } catch (err) {}
      }

      /*
       * Cryptographically secure pseudorandom number generator
       *
       * As Math.random() is cryptographically not safe to use
       */
      var cryptoSecureRandomInt = function () {
        if (crypto) {
          // Use getRandomValues method (Browser)
          if (typeof crypto.getRandomValues === 'function') {
            try {
              return crypto.getRandomValues(new Uint32Array(1))[0]
            } catch (err) {}
          }

          // Use randomBytes method (NodeJS)
          if (typeof crypto.randomBytes === 'function') {
            try {
              return crypto.randomBytes(4).readInt32LE()
            } catch (err) {}
          }
        }

        throw new Error('Native crypto module could not be used to get secure random number.')
      }

      /*
	     * Local polyfill of Object.create

	     */
      var create =
        Object.create ||
        (function () {
          function F() {}

          return function (obj) {
            var subtype

            F.prototype = obj

            subtype = new F()

            F.prototype = null

            return subtype
          }
        })()

      /**
       * CryptoJS namespace.
       */
      var C = {}

      /**
       * Library namespace.
       */
      var C_lib = (C.lib = {})

      /**
       * Base object for prototypal inheritance.
       */
      var Base = (C_lib.Base = (function () {
        return {
          /**
           * Creates a new object that inherits from this object.
           *
           * @param {Object} overrides Properties to copy into the new object.
           *
           * @return {Object} The new object.
           *
           * @static
           *
           * @example
           *
           *     var MyType = CryptoJS.lib.Base.extend({
           *         field: 'value',
           *
           *         method: function () {
           *         }
           *     });
           */
          extend: function (overrides) {
            // Spawn
            var subtype = create(this)

            // Augment
            if (overrides) {
              subtype.mixIn(overrides)
            }

            // Create default initializer
            if (!subtype.hasOwnProperty('init') || this.init === subtype.init) {
              subtype.init = function () {
                subtype.$super.init.apply(this, arguments)
              }
            }

            // Initializer's prototype is the subtype object
            subtype.init.prototype = subtype

            // Reference supertype
            subtype.$super = this

            return subtype
          },

          /**
           * Extends this object and runs the init method.
           * Arguments to create() will be passed to init().
           *
           * @return {Object} The new object.
           *
           * @static
           *
           * @example
           *
           *     var instance = MyType.create();
           */
          create: function () {
            var instance = this.extend()
            instance.init.apply(instance, arguments)

            return instance
          },

          /**
           * Initializes a newly created object.
           * Override this method to add some logic when your objects are created.
           *
           * @example
           *
           *     var MyType = CryptoJS.lib.Base.extend({
           *         init: function () {
           *             // ...
           *         }
           *     });
           */
          init: function () {},

          /**
           * Copies properties into this object.
           *
           * @param {Object} properties The properties to mix in.
           *
           * @example
           *
           *     MyType.mixIn({
           *         field: 'value'
           *     });
           */
          mixIn: function (properties) {
            for (var propertyName in properties) {
              if (properties.hasOwnProperty(propertyName)) {
                this[propertyName] = properties[propertyName]
              }
            }

            // IE won't copy toString using the loop above
            if (properties.hasOwnProperty('toString')) {
              this.toString = properties.toString
            }
          },

          /**
           * Creates a copy of this object.
           *
           * @return {Object} The clone.
           *
           * @example
           *
           *     var clone = instance.clone();
           */
          clone: function () {
            return this.init.prototype.extend(this)
          },
        }
      })())

      /**
       * An array of 32-bit words.
       *
       * @property {Array} words The array of 32-bit words.
       * @property {number} sigBytes The number of significant bytes in this word array.
       */
      var WordArray = (C_lib.WordArray = Base.extend({
        /**
         * Initializes a newly created word array.
         *
         * @param {Array} words (Optional) An array of 32-bit words.
         * @param {number} sigBytes (Optional) The number of significant bytes in the words.
         *
         * @example
         *
         *     var wordArray = CryptoJS.lib.WordArray.create();
         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);
         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);
         */
        init: function (words, sigBytes) {
          words = this.words = words || []

          if (sigBytes != undefined) {
            this.sigBytes = sigBytes
          } else {
            this.sigBytes = words.length * 4
          }
        },

        /**
         * Converts this word array to a string.
         *
         * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex
         *
         * @return {string} The stringified word array.
         *
         * @example
         *
         *     var string = wordArray + '';
         *     var string = wordArray.toString();
         *     var string = wordArray.toString(CryptoJS.enc.Utf8);
         */
        toString: function (encoder) {
          return (encoder || Hex).stringify(this)
        },

        /**
         * Concatenates a word array to this word array.
         *
         * @param {WordArray} wordArray The word array to append.
         *
         * @return {WordArray} This word array.
         *
         * @example
         *
         *     wordArray1.concat(wordArray2);
         */
        concat: function (wordArray) {
          // Shortcuts
          var thisWords = this.words
          var thatWords = wordArray.words
          var thisSigBytes = this.sigBytes
          var thatSigBytes = wordArray.sigBytes

          // Clamp excess bits
          this.clamp()

          // Concat
          if (thisSigBytes % 4) {
            // Copy one byte at a time
            for (var i = 0; i < thatSigBytes; i++) {
              var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff
              thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8)
            }
          } else {
            // Copy one word at a time
            for (var j = 0; j < thatSigBytes; j += 4) {
              thisWords[(thisSigBytes + j) >>> 2] = thatWords[j >>> 2]
            }
          }
          this.sigBytes += thatSigBytes

          // Chainable
          return this
        },

        /**
         * Removes insignificant bits.
         *
         * @example
         *
         *     wordArray.clamp();
         */
        clamp: function () {
          // Shortcuts
          var words = this.words
          var sigBytes = this.sigBytes

          // Clamp
          words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8)
          words.length = Math.ceil(sigBytes / 4)
        },

        /**
         * Creates a copy of this word array.
         *
         * @return {WordArray} The clone.
         *
         * @example
         *
         *     var clone = wordArray.clone();
         */
        clone: function () {
          var clone = Base.clone.call(this)
          clone.words = this.words.slice(0)

          return clone
        },

        /**
         * Creates a word array filled with random bytes.
         *
         * @param {number} nBytes The number of random bytes to generate.
         *
         * @return {WordArray} The random word array.
         *
         * @static
         *
         * @example
         *
         *     var wordArray = CryptoJS.lib.WordArray.random(16);
         */
        random: function (nBytes) {
          var words = []

          for (var i = 0; i < nBytes; i += 4) {
            words.push(cryptoSecureRandomInt())
          }

          return new WordArray.init(words, nBytes)
        },
      }))

      /**
       * Encoder namespace.
       */
      var C_enc = (C.enc = {})

      /**
       * Hex encoding strategy.
       */
      var Hex = (C_enc.Hex = {
        /**
         * Converts a word array to a hex string.
         *
         * @param {WordArray} wordArray The word array.
         *
         * @return {string} The hex string.
         *
         * @static
         *
         * @example
         *
         *     var hexString = CryptoJS.enc.Hex.stringify(wordArray);
         */
        stringify: function (wordArray) {
          // Shortcuts
          var words = wordArray.words
          var sigBytes = wordArray.sigBytes

          // Convert
          var hexChars = []
          // 源代码
          for (var i = 0; i < sigBytes; i++) {
            var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff
            hexChars.push((bite >>> 4).toString(16))
            hexChars.push((bite & 0x0f).toString(16))
          }
          return hexChars.join('')
        },

        /**
         * Converts a hex string to a word array.
         *
         * @param {string} hexStr The hex string.
         *
         * @return {WordArray} The word array.
         *
         * @static
         *
         * @example
         *
         *     var wordArray = CryptoJS.enc.Hex.parse(hexString);
         */
        parse: function (hexStr) {
          // Shortcut
          var hexStrLength = hexStr.length

          // Convert
          var words = []
          for (var i = 0; i < hexStrLength; i += 2) {
            words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4)
          }

          return new WordArray.init(words, hexStrLength / 2)
        },
      })

      /**
       * Latin1 encoding strategy.
       */
      var Latin1 = (C_enc.Latin1 = {
        /**
         * Converts a word array to a Latin1 string.
         *
         * @param {WordArray} wordArray The word array.
         *
         * @return {string} The Latin1 string.
         *
         * @static
         *
         * @example
         *
         *     var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);
         */
        stringify: function (wordArray) {
          // Shortcuts
          var words = wordArray.words
          var sigBytes = wordArray.sigBytes

          // Convert
          var latin1Chars = []
          for (var i = 0; i < sigBytes; i++) {
            var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff
            latin1Chars.push(String.fromCharCode(bite))
          }

          return latin1Chars.join('')
        },

        /**
         * Converts a Latin1 string to a word array.
         *
         * @param {string} latin1Str The Latin1 string.
         *
         * @return {WordArray} The word array.
         *
         * @static
         *
         * @example
         *
         *     var wordArray = CryptoJS.enc.Latin1.parse(latin1String);
         */
        parse: function (latin1Str) {
          // Shortcut
          var latin1StrLength = latin1Str.length

          // Convert
          var words = []
          for (var i = 0; i < latin1StrLength; i++) {
            words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8)
          }

          return new WordArray.init(words, latin1StrLength)
        },
      })

      /**
       * UTF-8 encoding strategy.
       */
      var Utf8 = (C_enc.Utf8 = {
        /**
         * Converts a word array to a UTF-8 string.
         *
         * @param {WordArray} wordArray The word array.
         *
         * @return {string} The UTF-8 string.
         *
         * @static
         *
         * @example
         *
         *     var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);
         */
        stringify: function (wordArray) {
          try {
            return decodeURIComponent(escape(Latin1.stringify(wordArray)))
          } catch (e) {
            throw new Error('Malformed UTF-8 data')
          }
        },

        /**
         * Converts a UTF-8 string to a word array.
         *
         * @param {string} utf8Str The UTF-8 string.
         *
         * @return {WordArray} The word array.
         *
         * @static
         *
         * @example
         *
         *     var wordArray = CryptoJS.enc.Utf8.parse(utf8String);
         */
        parse: function (utf8Str) {
          return Latin1.parse(unescape(encodeURIComponent(utf8Str)))
        },
      })

      /**
       * Abstract buffered block algorithm template.
       *
       * The property blockSize must be implemented in a concrete subtype.
       *
       * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0
       */
      var BufferedBlockAlgorithm = (C_lib.BufferedBlockAlgorithm = Base.extend({
        /**
         * Resets this block algorithm's data buffer to its initial state.
         *
         * @example
         *
         *     bufferedBlockAlgorithm.reset();
         */
        reset: function () {
          // Initial values
          this._data = new WordArray.init()
          this._nDataBytes = 0
        },

        /**
         * Adds new data to this block algorithm's buffer.
         *
         * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.
         *
         * @example
         *
         *     bufferedBlockAlgorithm._append('data');
         *     bufferedBlockAlgorithm._append(wordArray);
         */
        _append: function (data) {
          // Convert string to WordArray, else assume WordArray already
          if (typeof data == 'string') {
            data = Utf8.parse(data)
          }

          // Append
          this._data.concat(data)
          this._nDataBytes += data.sigBytes
        },

        /**
         * Processes available data blocks.
         *
         * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.
         *
         * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.
         *
         * @return {WordArray} The processed data.
         *
         * @example
         *
         *     var processedData = bufferedBlockAlgorithm._process();
         *     var processedData = bufferedBlockAlgorithm._process(!!'flush');
         */
        _process: function (doFlush) {
          var processedWords

          // Shortcuts
          var data = this._data
          var dataWords = data.words
          var dataSigBytes = data.sigBytes
          var blockSize = this.blockSize
          var blockSizeBytes = blockSize * 4

          // Count blocks ready
          var nBlocksReady = dataSigBytes / blockSizeBytes
          if (doFlush) {
            // Round up to include partial blocks
            nBlocksReady = Math.ceil(nBlocksReady)
          } else {
            // Round down to include only full blocks,
            // less the number of blocks that must remain in the buffer
            nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0)
          }

          // Count words ready
          var nWordsReady = nBlocksReady * blockSize

          // Count bytes ready
          var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes)

          // Process blocks
          if (nWordsReady) {
            for (var offset = 0; offset < nWordsReady; offset += blockSize) {
              // Perform concrete-algorithm logic
              this._doProcessBlock(dataWords, offset)
            }

            // Remove processed words
            processedWords = dataWords.splice(0, nWordsReady)
            data.sigBytes -= nBytesReady
          }

          // Return processed words
          return new WordArray.init(processedWords, nBytesReady)
        },

        /**
         * Creates a copy of this object.
         *
         * @return {Object} The clone.
         *
         * @example
         *
         *     var clone = bufferedBlockAlgorithm.clone();
         */
        clone: function () {
          var clone = Base.clone.call(this)
          clone._data = this._data.clone()

          return clone
        },

        _minBufferSize: 0,
      }))

      /**
       * Abstract hasher template.
       *
       * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits)
       */
      var Hasher = (C_lib.Hasher = BufferedBlockAlgorithm.extend({
        /**
         * Configuration options.
         */
        cfg: Base.extend(),

        /**
         * Initializes a newly created hasher.
         *
         * @param {Object} cfg (Optional) The configuration options to use for this hash computation.
         *
         * @example
         *
         *     var hasher = CryptoJS.algo.SHA256.create();
         */
        init: function (cfg) {
          // Apply config defaults
          this.cfg = this.cfg.extend(cfg)

          // Set initial values
          this.reset()
        },

        /**
         * Resets this hasher to its initial state.
         *
         * @example
         *
         *     hasher.reset();
         */
        reset: function () {
          // Reset data buffer
          BufferedBlockAlgorithm.reset.call(this)

          // Perform concrete-hasher logic
          this._doReset()
        },

        /**
         * Updates this hasher with a message.
         *
         * @param {WordArray|string} messageUpdate The message to append.
         *
         * @return {Hasher} This hasher.
         *
         * @example
         *
         *     hasher.update('message');
         *     hasher.update(wordArray);
         */
        update: function (messageUpdate) {
          // Append
          this._append(messageUpdate)

          // Update the hash
          this._process()

          // Chainable
          return this
        },

        /**
         * Finalizes the hash computation.
         * Note that the finalize operation is effectively a destructive, read-once operation.
         *
         * @param {WordArray|string} messageUpdate (Optional) A final message update.
         *
         * @return {WordArray} The hash.
         *
         * @example
         *
         *     var hash = hasher.finalize();
         *     var hash = hasher.finalize('message');
         *     var hash = hasher.finalize(wordArray);
         */
        finalize: function (messageUpdate) {
          // Final message update
          if (messageUpdate) {
            this._append(messageUpdate)
          }

          // Perform concrete-hasher logic
          var hash = this._doFinalize()

          return hash
        },

        blockSize: 512 / 32,

        /**
         * Creates a shortcut function to a hasher's object interface.
         *
         * @param {Hasher} hasher The hasher to create a helper for.
         *
         * @return {Function} The shortcut function.
         *
         * @static
         *
         * @example
         *
         *     var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);
         */
        _createHelper: function (hasher) {
          return function (message, cfg) {
            return new hasher.init(cfg).finalize(message)
          }
        },

        /**
         * Creates a shortcut function to the HMAC's object interface.
         *
         * @param {Hasher} hasher The hasher to use in this HMAC helper.
         *
         * @return {Function} The shortcut function.
         *
         * @static
         *
         * @example
         *
         *     var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);
         */
        _createHmacHelper: function (hasher) {
          return function (message, key) {
            return new C_algo.HMAC.init(hasher, key).finalize(message)
          }
        },
      }))

      /**
       * Algorithm namespace.
       */
      var C_algo = (C.algo = {})

      return C
    })(Math)

  return CryptoJS
})
